//
//
//
//    COMPILER
//
//
//


#include "synt_analys.h"
#include <io.h>


#define EQUAL(name, str, number)   if (tree->data.flag == name)   { fprintf (out, #name); fprintf (out, "\n"); }


char* ReadFromFile (char FileName[], int* FileLength);

int Compile_Main(char* file , tree_t* tree);
int Compile_Scope(FILE* out , tree_t* tree);
int Compile_New(FILE* out, tree_t* tree);
int Compile_Math(FILE* out, tree_t* node);

int Copmile_if(FILE* out , tree_t* tree);
int Compile_while(FILE* out, tree_t* tree);

int CompileCond   (FILE* out, tree_t* tree);
int Compile_konsole(FILE* out , tree_t* tree);

int Compile_Ravno (FILE* out, tree_t* tree);

int operation_number = 0;

//=========================================================================================================================================================


int main()
{

    int FileLength = 0;
    char* str = ReadFromFile ("M16.txt", &FileLength);

    strcpy(input , str);
    printf("%s" , input);


    box_num = 0;

    info_tree* boxes = (info_tree*)calloc(MAX_BOXES_NUMBER , sizeof(*boxes));
    Lexical_analysis(boxes);

    tree_t* main_tree = Get_Scope(boxes);

    Compile_Main("out.txt" , main_tree);

    return 0;

}

//=========================================================================================================================================================

int Compile_Main(char* file , tree_t* tree)
{

    assert(tree);
    assert(file);

    FILE* out = fopen(file , "w");

    Compile_Scope(out , tree);

    fprintf(out , "EXIT\n");

    return 1;

}

int Compile_Scope(FILE* out , tree_t* tree)
{

    assert (out);
    assert (tree);

    if (tree->data.flag == CONNECTION_TYPE)
    {
        Compile_Scope(out, tree->left );
        Compile_Scope(out, tree->right);
    }

    else if (tree->data.flag == NEW_VARIABLE_UZEL)
    {

        Compile_New(out, tree);

    }

    else
    {

        if(tree->data.flag == RAVNO)
        {

            Compile_Ravno (out, tree);

        }

        if(tree->data.flag == WHILE )
        {

            Compile_while(out, tree);

        }

        if(tree->data.flag == IF)
        {

            Copmile_if(out , tree);

        }

        if((tree->data.flag == IN) || (tree->data.flag == OUT))

        {

            Compile_konsole(out, tree);

        }

    }

    return 1;
}


int Compile_New(FILE* out, tree_t* tree)
{

    assert (out );
    assert (tree);

    fprintf (out, "pushar %s\n", tree->data.var);

    if (tree->left)
    {

        Compile_Math  (out, tree->left);
        fprintf (out, "pop %s\n", tree->data.var);

    }

    return 1;

}

int Compile_Ravno (FILE* out, tree_t* tree)
{
    assert (out );
    assert (tree);

    Compile_Math (out, tree->right);

    fprintf (out, "pop %s\n", tree->left->data.var);

    return 1;
}


int Compile_Math(FILE* out, tree_t* tree)
{

    assert (out );
    assert (tree);

    if (tree->data.flag == CHISLO_TYPE)
    {

        fprintf (out, "push %d\n", tree->data.value);

    }

    else if (tree->data.flag == VAR_TYPE)
    {

        fprintf (out, "pushar %s\n", tree->data.var);

    }

    else
    {

        Compile_Math (out, tree->left );
        Compile_Math (out, tree->right);

        #include "TYPES.h"

    }

    return 1;

}

int Compile_while(FILE* out, tree_t* tree)
{

    assert (out );
    assert (tree);

    int iswhile = (tree->data.flag == WHILE);

    fprintf (out, ":again %d\n", operation_number);

    CompileCond (out, tree->right);

    fprintf (out, "JNT\n");
    fprintf (out, "END_WHILE %d\n", operation_number);

    Compile_Scope (out, tree->left);

    fprintf (out, ":JMP again%d\n", operation_number);
    fprintf (out, ":END_WHILE%d\n", operation_number);
    operation_number++;

    return 1;

}


int Compile_konsole(FILE* out, tree_t* tree)
{

    assert (out );
    assert (tree);

    if (tree->data.flag == IN  ) fprintf (out, "in" );
    if (tree->data.flag == OUT ) fprintf (out, "OUT");

    fprintf (out, " %s\n", tree->data.value);

    return 1;

}

int Copmile_if(FILE* out , tree_t* tree)
{

    assert(out );
    assert(tree);

    CompileCond (out , tree->right);

    fprintf (out , "JNT ");

    fprintf (out , "endif%d\n" , operation_number);

    Compile_Scope(out , tree->left);

    fprintf (out,  ":endif%d\n"   , operation_number); operation_number++ ;

    return 1;

}

int CompileCond   (FILE* out, tree_t* tree)
{
    assert (out );
    assert (tree);

    int check = ((tree->data.flag == AND ) || (tree->data.flag == ILI) ||  (tree->data.flag == NO));

    if (check)
    {

        CompileCond (out, tree->left );
        CompileCond (out, tree->right);

        #include "TYPES.h"

    }

    else
    {

        Compile_Math (out, tree->left );
        Compile_Math (out, tree->right);

        #include "TYPES.h"

    }

    return 1;
}


//============================================================================================




char* ReadFromFile (char FileName[], int* FileLength)
{

    FILE* in = fopen (FileName, "r");

    *FileLength  = filelength (fileno (in));

    char* text = (char*) calloc (*FileLength, sizeof (char));

    fread (text, *FileLength, sizeof (char), in);

    fclose(in);

    return text;

}
